package process

import (
	"awesome-devops/applications/models"
	"awesome-devops/applications/tools"
	"awesome-devops/helper"
	"fmt"
	"gitee.com/jjawesomejj/awesome-util/config"
	"gitee.com/jjawesomejj/awesome-util/helper/commonhelper"
	"strconv"
)

//输出需要发布到目标机器
const NEED_UPLOAD = 1

type ProcessConfig struct {
	gitCommand    tools.GitCommand
	PublishConfig models.Process
}

func (processConfig *ProcessConfig) Init() error {
	command, err := models.GetDeployGitCommand(*processConfig.PublishConfig.GetProject())
	if err != nil {
		return err
	}
	processConfig.gitCommand = *command
	return nil
}

func (processConfig *ProcessConfig) GetGitCommand() tools.GitCommand {
	return processConfig.gitCommand
}

func GetProcessConfigByProcess(project *models.Project, publishConfig models.Process, deploy models.Deploy, standard *tools.Standard) (*ProcessConfig, error) {
	process := ProcessConfig{
		PublishConfig: publishConfig,
	}
	err := process.Init()
	if err != nil {
		return &ProcessConfig{}, err
	}
	process.gitCommand.SetStd(standard)
	_, err = process.gitCommand.PullAll(project.Branch)
	if err != nil {
		return nil, err
	}
	_, err = process.gitCommand.ResetHard(deploy.CommitId)
	if err != nil {
		return nil, err
	}
	tag, err := process.gitCommand.GetTag()
	if err != nil {
		return nil, err
	}
	process.PublishConfig.SetEnv("git_tag", tag)
	message, err := process.gitCommand.GetCommitMessage(deploy.CommitId)
	if err != nil {
		return nil, err
	}
	process.PublishConfig.SetEnv("git_commit_message", message)

	return &process, nil
}

func (processConfig *ProcessConfig) RunStep(std *tools.Standard, project models.Project, deploy models.Deploy, standardPool *[]*tools.Standard) (output []map[string]interface{}, error error) {
	processConfig.PublishConfig.GetServers()
	steps := processConfig.PublishConfig.GetRunStep()
	gitCommand := processConfig.gitCommand
	envArgs := map[string]string{
		"work_dir":   gitCommand.GitProjectPath,
		"git_url":    gitCommand.GitSshUrl,
		"git_branch": project.Branch,
		"git_commit": deploy.CommitId,
		"ssh_pub": config.GetConfigByKey("ssh_pub", func() interface{} {
			return ""
		}).(string),
		"ssh_private": config.GetConfigByKey("ssh_private", func() interface{} {
			return ""
		}).(string),
	}
	runFiles := processConfig.PublishConfig.GetRunFiles()
	for _, step := range steps {
		shell, err := step.GetRunShell(envArgs, processConfig.PublishConfig.GetRunningEnv())
		fmt.Println(shell)
		if err != nil {
			return nil, err
		}
		models.WriteOpsFiles(runFiles, gitCommand.GetProjectAbsDir(), envArgs, processConfig.PublishConfig.GetRunningEnv())
		Runner, err := step.GetRunningDriver(&gitCommand, envArgs, processConfig.PublishConfig.GetRunningEnv(), gitCommand.GitProjectPath)
		if err != nil {
			return nil, err
		}
		Runner.SetTimeOutHandler(func() (time int, echoWords string, callBack func()) {
			return step.GetBuildTimeout(), commonhelper.Format("构建超时,项目名称:【{}】步骤名称【{}】--buildTimeout=设置构建超时时间",
					processConfig.PublishConfig.Name, step.StepName),
				nil
		})
		Runner.SetStd(std)
		log, err := Runner.Run()
		//合并程序输出的环境变量
		processConfig.PublishConfig.MergeEnv(helper.GetRunningEnvParams(log))

		if err != nil {
			return nil, err
		}
	}
	afterUploadStep := processConfig.PublishConfig.GetAfterRunStep()
	//开始执行发布流程
	if processConfig.PublishConfig.NeedUpload == NEED_UPLOAD {
		for _, server := range processConfig.PublishConfig.GetServers() {
			StdWithServer := tools.GetTaskStand(std.TaskId, server.FormatServerName(), standardPool)
			StdWithServer.Stdout.MessageChan = std.Stdout.MessageChan
			defaultTimeOut := config.GetConfigByKey("rsynctimeout", func() interface{} {
				return float64(30)
			})
			timeout := processConfig.PublishConfig.GetExtParams("rsynctimeout", strconv.Itoa(int(defaultTimeOut.(float64))))
			timeoutInt, err := strconv.Atoi(timeout)
			if err != nil {
				fmt.Println(commonhelper.Format("无效的rsynctimeout参数:{} 项目名称:{},使用默认参数{}",
					timeout,
					processConfig.PublishConfig.Name,
					strconv.Itoa(int(defaultTimeOut.(float64)))))
				timeoutInt = int(defaultTimeOut.(float64))
			}
			rsync := tools.Rsync{
				SshUser:       server.SshUser,
				Port:          server.SshPort,
				IpAddress:     server.SshIp,
				SourceDir:     gitCommand.GitProjectPath + "/" + processConfig.PublishConfig.OutputDir,
				DestDir:       processConfig.PublishConfig.UploadDir,
				ExcludeString: processConfig.PublishConfig.UploadExcludeDir,
				Std:           std,
				TimeOut:       timeoutInt,
			}
			uploadLog, err := rsync.Upload()
			if err != nil {
				tools.GetLogger().Error("rsync上传异常:" + err.Error())
				return nil, err
			}
			fmt.Println(uploadLog, "upload_dir")
			tools.GetLogger().Info("开始执行后置钩子")
			for _, hook := range afterUploadStep {
				runner, err := hook.GetAfterRunningDriver(&server, make(map[string]string), processConfig.PublishConfig.GetRunningEnv(), processConfig.PublishConfig.UploadDir)
				if err == nil {
					runner.SetStd(StdWithServer)
					runner.SetTimeOutHandler(func() (time int, echoWords string, callBack func()) {
						return hook.GetBuildTimeout(), commonhelper.Format("构建超时,项目名称:【{}】步骤名称【{}】--buildTimeout=设置构建超时时间",
							processConfig.PublishConfig.Name, hook.StepName), nil
					})
					stream, err2 := runner.Run()
					if err2 != nil {
						return nil, err2
					}
					//合并程序输出的环境变量
					processConfig.PublishConfig.MergeEnv(helper.GetRunningEnvParams(stream.Stdout.GetDataString()))
				}
			}
		}
	}
	return make([]map[string]interface{}, 0), nil
}
